## Copyright 2015-2019 Ilgar Lunin, Pedro Cabrera

## Licensed under the Apache License, Version 2.0 (the "License");
## you may not use this file except in compliance with the License.
## You may obtain a copy of the License at

##     http://www.apache.org/licenses/LICENSE-2.0

## Unless required by applicable law or agreed to in writing, software
## distributed under the License is distributed on an "AS IS" BASIS,
## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
## See the License for the specific language governing permissions and
## limitations under the License.


from PyFlow.Tests.TestsBase import *
from PyFlow.Core.Common import *
from collections import Counter
from PyFlow.Input import *
import time


class TestGeneral(unittest.TestCase):
    def setUp(self):
        print("\t[BEGIN TEST]", self._testMethodName)

    def tearDown(self):
        print("--------------------------------\n")

    def test_connect_pins_by_indexes(self):
        man = GraphManager()
        packages = GET_PACKAGES()
        mathLib = packages["PyFlowBase"].GetFunctionLibraries()["MathAbstractLib"]
        defaultLib = packages["PyFlowBase"].GetFunctionLibraries()["DefaultLib"]
        classNodes = packages["PyFlowBase"].GetNodeClasses()
        foos = mathLib.getFunctions()
        defaultLibFoos = defaultLib.getFunctions()

        makeIntNode = NodeBase.initializeFromFunction(defaultLibFoos["makeInt"])
        addNode2 = NodeBase.initializeFromFunction(foos["add"])
        printNode = classNodes["consoleOutput"]("print")

        man.activeGraph().addNode(makeIntNode)
        man.activeGraph().addNode(addNode2)
        man.activeGraph().addNode(printNode)

        makeIntNode.setData("i", 5)

        connection = connectPinsByIndexes(makeIntNode, 1, addNode2, 1)
        self.assertEqual(connection, True, "FAILED TO ADD EDGE")

        connection = connectPinsByIndexes(addNode2, 1, printNode, 2)
        self.assertEqual(connection, True, "FAILED TO ADD EDGE")
        printNode[DEFAULT_IN_EXEC_NAME].call()

        self.assertEqual(addNode2.getData("out"), 5, "NODES EVALUATION IS INCORRECT")

    def test_graph_location(self):
        packages = GET_PACKAGES()
        man = GraphManager()
        subgraphNodeClass = packages["PyFlowBase"].GetNodeClasses()["compound"]
        subgraphNodeInstance = subgraphNodeClass(str("compound"))
        man.activeGraph().addNode(subgraphNodeInstance)

        # step inside compound
        man.selectGraphByName(subgraphNodeInstance.name)
        self.assertEqual(
            Counter(man.location()),
            Counter([man.findRootGraph().name, subgraphNodeInstance.name]),
        )
        self.assertEqual(
            Counter(subgraphNodeInstance.rawGraph.location()), Counter(man.location())
        )

    def test_add_int_no_exec(self):
        man = GraphManager()
        packages = GET_PACKAGES()
        mathLib = packages["PyFlowBase"].GetFunctionLibraries()["MathAbstractLib"]
        defaultLib = packages["PyFlowBase"].GetFunctionLibraries()["DefaultLib"]
        classNodes = packages["PyFlowBase"].GetNodeClasses()
        foos = mathLib.getFunctions()
        defaultLibFoos = defaultLib.getFunctions()

        makeIntNode = NodeBase.initializeFromFunction(defaultLibFoos["makeInt"])
        addNode2 = NodeBase.initializeFromFunction(foos["add"])
        printNode = classNodes["consoleOutput"]("print")

        man.activeGraph().addNode(makeIntNode)
        man.activeGraph().addNode(addNode2)
        man.activeGraph().addNode(printNode)

        makeIntNode.setData("i", 5)

        connection = connectPins(makeIntNode[str("out")], addNode2[str("a")])
        self.assertEqual(connection, True, "FAILED TO ADD EDGE")

        connection = connectPins(addNode2[str("out")], printNode[str("entity")])
        self.assertEqual(connection, True, "FAILED TO ADD EDGE")
        printNode[DEFAULT_IN_EXEC_NAME].call()

        self.assertEqual(addNode2.getData("out"), 5, "NODES EVALUATION IS INCORRECT")

    def test_foo_node_ref_set_data(self):
        packages = GET_PACKAGES()
        randomLib = packages["PyFlowBase"].GetFunctionLibraries()["RandomLib"]
        defaultLib = packages["PyFlowBase"].GetFunctionLibraries()["DefaultLib"]
        classNodes = packages["PyFlowBase"].GetNodeClasses()
        randomLibFoos = randomLib.getFunctions()
        defaultLibFoos = defaultLib.getFunctions()

        randintNode = NodeBase.initializeFromFunction(randomLibFoos["randint"])
        printNode = classNodes["consoleOutput"]("print")

        man = GraphManager()

        man.activeGraph().addNode(randintNode)
        man.activeGraph().addNode(printNode)

        self.assertIsNotNone(randintNode)
        self.assertIsNotNone(printNode)

        pPrintInputValuePin = printNode[str("entity")]

        edge2Created = connectPins(randintNode[str("Result")], pPrintInputValuePin)
        self.assertEqual(edge2Created, True, "FAILED TO CONNECT INT AND ANY")

        values = set()
        for i in range(10):
            printNode[DEFAULT_IN_EXEC_NAME].call()
            values.add(pPrintInputValuePin.currentData())
        self.assertGreater(len(values), 1)

    def test_reconnect_value(self):
        packages = GET_PACKAGES()

        defaultLib = packages["PyFlowBase"].GetFunctionLibraries()["DefaultLib"]
        foos = defaultLib.getFunctions()

        n1 = NodeBase.initializeFromFunction(foos["makeBool"])
        n2 = NodeBase.initializeFromFunction(foos["makeBool"])
        n3 = NodeBase.initializeFromFunction(foos["makeBool"])

        man = GraphManager()
        man.activeGraph().addNode(n1)
        man.activeGraph().addNode(n2)
        man.activeGraph().addNode(n3)

        n1Out = n1.getPinSG(str("out"), PinSelectionGroup.Outputs)
        n3b = n3.getPinSG(str("b"), PinSelectionGroup.Inputs)
        # connect n1.out and n3.b
        c1 = connectPins(n1Out, n3b)
        # check connection was created
        self.assertEqual(c1, True)
        # check n1.out affects on n3.b
        self.assertEqual(n3b in n1Out.affects, True)
        # check n3.b affected by n1.out
        self.assertEqual(n1Out in n3b.affected_by, True)

        n2Out = n2.getPinSG(str("out"), PinSelectionGroup.Outputs)
        # connect n2.out to n3.b
        # n3.b is connected with n1.out
        # we expect n3.b breaks all connections before connecting with n2.out
        c2 = connectPins(n2Out, n3b)
        # check connections successful
        self.assertEqual(c2, True)
        # check n2.out affects on n3.b
        self.assertEqual(n3b in n2Out.affects, True, "incorrect connection")
        # check n3.b affected by n2.out
        self.assertEqual(n2Out in n3b.affected_by, True, "incorrect")
        # check n1.out really disconnected
        self.assertEqual(n1Out.affects, set(), "not cleared")

    def test_are_pins_connected(self):
        packages = GET_PACKAGES()
        intlib = packages["PyFlowBase"].GetFunctionLibraries()["MathAbstractLib"]
        foos = intlib.getFunctions()

        addNode1 = NodeBase.initializeFromFunction(foos["add"])
        addNode2 = NodeBase.initializeFromFunction(foos["add"])

        man = GraphManager()

        man.activeGraph().addNode(addNode1)
        man.activeGraph().addNode(addNode2)

        pinOut = addNode1.getPinSG(str("out"), PinSelectionGroup.Outputs)
        pinInp = addNode2.getPinSG(str("a"), PinSelectionGroup.Inputs)
        bConnected = connectPins(pinOut, pinInp)
        self.assertEqual(bConnected, True, "FAILED TO ADD EDGE")
        self.assertEqual(arePinsConnected(pinOut, pinInp), True)

        disconnected = disconnectPins(pinInp, pinOut)
        self.assertEqual(disconnected, True, "pins are not disconnected")
        self.assertEqual(arePinsConnected(pinOut, pinInp), False)

    def test_create_var(self):
        man = GraphManager()
        v1 = man.activeGraph().createVariable()
        self.assertEqual(v1.uid in man.activeGraph().getVars(), True)

    def test_variable_scope(self):
        man = GraphManager()
        # add variable to root graph
        rootVariable = man.activeGraph().createVariable(name="v0")
        rootVariable.value = 0
        self.assertEqual(rootVariable.uid in man.activeGraph().getVars(), True)

        vars = man.activeGraph().getVarList()
        self.assertEqual(len(vars), 1, "failed to gather variables")

        # create two subgraphs and variables inside
        packages = GET_PACKAGES()
        subgraphNodeClass = packages["PyFlowBase"].GetNodeClasses()["compound"]
        varGetterClass = packages["PyFlowBase"].GetNodeClasses()["getVar"]
        varSetterClass = packages["PyFlowBase"].GetNodeClasses()["setVar"]

        subgraphNodeInstance1 = subgraphNodeClass("subgraph1")
        subgraphNodeInstance2 = subgraphNodeClass("subgraph2")
        self.assertEqual(man.activeGraph().addNode(subgraphNodeInstance1), True)
        self.assertEqual(man.activeGraph().addNode(subgraphNodeInstance2), True)

        # goto subgraph1 and create variable
        man.selectGraphByName(subgraphNodeInstance1.name)
        sg1Var = man.activeGraph().createVariable(name="v1")
        sg1Var.value = 1
        v1Getter = varGetterClass("v1Get", sg1Var)
        v1Setter = varSetterClass("v1Set", sg1Var)
        self.assertEqual(man.activeGraph().addNode(v1Getter), True)
        self.assertEqual(man.activeGraph().addNode(v1Setter), True)
        man.selectRootGraph()

        # Check variables scope visibility
        self.assertEqual(
            man.activeGraph().addNode(v1Getter),
            False,
            "Variable access error! Variables in child graphs should not be visible to parent ones!",
        )
        self.assertEqual(
            man.activeGraph().addNode(v1Setter),
            False,
            "Variable access error! Variables in child graphs should not be visible to parent ones!",
        )

        # goto subgraph2 and create variable there
        man.selectGraphByName(subgraphNodeInstance2.name)
        sg2Var = man.activeGraph().createVariable(name="v2")
        sg2Var.value = 2
        man.selectRootGraph()

        # ask variables from rootgraph.
        vars = man.activeGraph().getVarList()
        self.assertEqual(len(vars), 1, "failed to gather variables")
        # check variable value is 0
        self.assertEqual(vars[0].value, 0, "invalid variable")

        # go to subgraph1 and ask variables there
        man.selectGraphByName(subgraphNodeInstance1.name)
        vars = man.activeGraph().getVarList()
        # two variables. One from subgraph1 + one from root
        self.assertEqual(len(vars), 2, "failed to gather variables")
        varsValues = [i.value for i in vars]
        self.assertEqual(
            Counter(varsValues), Counter([0, 1]), "variables are incorrect"
        )
        man.selectRootGraph()

        # goto subgraph2 and ask variables there
        man.selectGraphByName(subgraphNodeInstance2.name)
        vars = man.activeGraph().getVarList()
        # two variables. One from subgraph2 + one from root
        self.assertEqual(len(vars), 2, "failed to gather variables")
        varsValues = [i.value for i in vars]
        self.assertEqual(
            Counter(varsValues), Counter([0, 2]), "variables are incorrect"
        )
        man.selectRootGraph()

    def test_get_bool_var(self):
        packages = GET_PACKAGES()
        classNodes = packages["PyFlowBase"].GetNodeClasses()

        man = GraphManager()

        # create bool variable
        v1 = man.activeGraph().createVariable(str("BoolPin"))
        v1.value = False

        # create variable getter node
        varGetterClass = packages["PyFlowBase"].GetNodeClasses()["getVar"]
        # since variable is bool, bool pin will be created
        varGetterInstance = varGetterClass(str("v1Getter"), v1)
        man.activeGraph().addNode(varGetterInstance)

        # create print node
        defaultLib = packages["PyFlowBase"].GetFunctionLibraries()["DefaultLib"]
        printerInstance = classNodes["consoleOutput"]("print")
        man.activeGraph().addNode(printerInstance)

        # connect to print node input
        varOutPin = varGetterInstance.getPinSG(str("out"), PinSelectionGroup.Outputs)
        printInPin = printerInstance.getPinSG(str("entity"), PinSelectionGroup.Inputs)
        printInExecPin = printerInstance.getPinSG(
            str("inExec"), PinSelectionGroup.Inputs
        )
        connected = connectPins(varOutPin, printInPin)
        self.assertEqual(connected, True, "var getter is not connected")

        # print variable value and check it
        printInExecPin.call()
        self.assertEqual(printInPin.currentData(), False)
        # next, change variable value (Not varGetterInstance varOutPin! Note we are not touching it anymore)
        # this will broadcast valueChanged on v1, which will trigger dirty propagation from varOutPin
        # varGetterInstance.onVarValueChanged and v1.valueChanged were connected in getVar.postCreate
        v1.value = True
        # following line will trigger compute on print node, which will ask data on it's inputs
        # Inputs on print node will be dirty, data will be asked on varGetterInstance varOutPin
        printInExecPin.call()
        self.assertEqual(printInPin.currentData(), True)

    def test_kill_variable(self):
        packages = GET_PACKAGES()

        man = GraphManager()

        # create any type variable
        v1 = man.activeGraph().createVariable()
        v1.value = False

        # create variable getter node
        varGetterClass = packages["PyFlowBase"].GetNodeClasses()["getVar"]
        varGetterInstance = varGetterClass(str("v1Getter"), v1)
        man.activeGraph().addNode(varGetterInstance)

        # create print node
        defaultLib = packages["PyFlowBase"].GetFunctionLibraries()["DefaultLib"]
        printerInstance = packages["PyFlowBase"].GetNodeClasses()["consoleOutput"](
            "print"
        )
        man.activeGraph().addNode(printerInstance)

        # connect to print node input
        varOutPin = varGetterInstance.getPinSG(str("out"), PinSelectionGroup.Outputs)
        printInPin = printerInstance.getPinSG(str("entity"), PinSelectionGroup.Inputs)
        printInExecPin = printerInstance.getPinSG(
            str("inExec"), PinSelectionGroup.Inputs
        )
        connected = connectPins(varOutPin, printInPin)
        self.assertEqual(connected, True, "var getter is not connected")

        man.activeGraph().killVariable(v1)
        self.assertEqual(
            v1 not in man.activeGraph().getVars(), True, "variable not killed"
        )

    def test_set_bool_var(self):
        packages = GET_PACKAGES()

        man = GraphManager()

        # create bool type variable
        v1 = man.activeGraph().createVariable(str("BoolPin"))
        # this will accept only bools
        v1.value = False

        # create variable setter node
        varSetterClass = packages["PyFlowBase"].GetNodeClasses()["setVar"]
        varSetterInstance = varSetterClass(str("v1Setter"), v1)
        setterAdded = man.activeGraph().addNode(varSetterInstance)
        self.assertEqual(setterAdded, True)

        # set new value to setter node input pin
        inExecPin = varSetterInstance.getPinSG(
            DEFAULT_IN_EXEC_NAME, PinSelectionGroup.Inputs
        )
        inPin = varSetterInstance.getPinSG(str("inp"), PinSelectionGroup.Inputs)
        outPin = varSetterInstance.getPinSG(str("out"), PinSelectionGroup.Outputs)
        self.assertIsNotNone(inExecPin)
        self.assertIsNotNone(inPin)
        self.assertIsNotNone(outPin)
        # next we set data to setter node
        inPin.setData(True)
        # And fire input exec pin.
        # We expect it will call compute
        # which will update variable value
        inExecPin.call()
        # check variable value
        self.assertEqual(v1.value, True, "variable value is not set")

    def test_subgraph_execs(self):
        packages = GET_PACKAGES()

        man = GraphManager()

        # create empty compound
        subgraphNodeClass = packages["PyFlowBase"].GetNodeClasses()["compound"]
        subgraphNodeInstance = subgraphNodeClass(str("compound"))
        man.activeGraph().addNode(subgraphNodeInstance)

        # step inside compound
        man.selectGraphByName(subgraphNodeInstance.name)
        # self.assertEqual(graph.name, subgraphNodeInstance.name, "failed to enter compound")

        # add input output nodes to expose pins to outer compound node
        inputs1 = man.activeGraph().getInputNode()
        outputs1 = man.activeGraph().getOutputNode()
        self.assertIsNotNone(inputs1, "failed to create graph inputs node")
        self.assertIsNotNone(outputs1, "failed to create graph outputs node")

        # create out pin on graphInputs node
        # this should expose input pin on compound node
        outPin = inputs1.addOutPin()
        man.Tick(0.02)
        self.assertEqual(
            len(subgraphNodeInstance.namePinInputsMap), 1, "failed to expose input pin"
        )
        self.assertEqual(
            list(subgraphNodeInstance.inputs.values())[0].name, outPin.name
        )
        outPin.setName("inAnyExec")

        # create input pin on graphOutputs node
        # this should expose output pin on compound node
        inPin = outputs1.addInPin()
        man.Tick(0.02)
        self.assertEqual(
            len(subgraphNodeInstance.namePinOutputsMap), 1, "failed to expose input pin"
        )
        self.assertEqual(
            list(subgraphNodeInstance.outputs.values())[0].name, inPin.name
        )
        inPin.setName("outAnyExec")

        subgraphInAnyExec = subgraphNodeInstance.getPinSG(
            str("inAnyExec"), PinSelectionGroup.Inputs
        )
        self.assertIsNotNone(
            subgraphInAnyExec, "failed to find compound input exec pin"
        )
        subgraphOutAnyExec = subgraphNodeInstance.getPinSG(
            str("outAnyExec"), PinSelectionGroup.Outputs
        )
        self.assertIsNotNone(subgraphOutAnyExec, "failed to find compound out exec pin")

        # add print node inside
        foos = (
            packages["PyFlowBase"].GetFunctionLibraries()["DefaultLib"].getFunctions()
        )

        printNode1 = packages["PyFlowBase"].GetNodeClasses()["consoleOutput"]("print")
        man.activeGraph().addNode(printNode1)
        printNode1.setData("entity", "hello from compound")

    def test_graph_serialization(self):
        man = GraphManager()
        packages = GET_PACKAGES()
        lib = packages["PyFlowBase"].GetFunctionLibraries()["MathAbstractLib"]
        defaultLib = packages["PyFlowBase"].GetFunctionLibraries()["DefaultLib"]
        classNodes = packages["PyFlowBase"].GetNodeClasses()
        foos = lib.getFunctions()
        defFoos = defaultLib.getFunctions()

        makeInt = NodeBase.initializeFromFunction(defFoos["makeInt"])
        addNode2 = NodeBase.initializeFromFunction(foos["add"])
        printNode = classNodes["consoleOutput"]("printer")

        man.activeGraph().addNode(makeInt)
        man.activeGraph().addNode(addNode2)
        man.activeGraph().addNode(printNode)

        makeInt.setData("i", 5)

        connected = connectPinsByIndexes(makeInt, 1, addNode2, 1)
        self.assertEqual(connected, True)

        connected = connectPinsByIndexes(addNode2, 1, printNode, 2)
        self.assertEqual(connected, True)

        printNode[DEFAULT_IN_EXEC_NAME].call()

        self.assertEqual(addNode2.orderedOutputs[1].currentData(), 5, "Incorrect calc")

        # save and clear
        dataJson = man.serialize()
        man.clear(keepRoot=False)

        # load
        man.deserialize(dataJson)

        restoredAddNode2 = man.activeGraph().findNode(str("makeInt"))
        printNode = man.activeGraph().findNode(str("printer"))
        printNode[DEFAULT_IN_EXEC_NAME].call()
        self.assertEqual(restoredAddNode2.getData("out"), 5, "Incorrect calc")

    def test_graph_depth(self):
        man = GraphManager()
        packages = GET_PACKAGES()

        subgraphNodeClass = packages["PyFlowBase"].GetNodeClasses()["compound"]
        subgraphNodeInstance = subgraphNodeClass(str(str("compound")))
        man.activeGraph().addNode(subgraphNodeInstance)

        self.assertEqual(man.activeGraph().depth(), 1)

        man.selectGraph(subgraphNodeInstance)
        self.assertEqual(man.activeGraph().depth(), 2)

    def test_manager_serialization(self):
        man = GraphManager()
        packages = GET_PACKAGES()

        subgraphNodeClass = packages["PyFlowBase"].GetNodeClasses()["compound"]
        subgraphNodeInstance = subgraphNodeClass(str("compound"))
        man.activeGraph().addNode(subgraphNodeInstance)
        man.selectGraph(subgraphNodeInstance)

        inputs1 = man.activeGraph().getInputNode()
        outputs1 = man.activeGraph().getOutputNode()

        # create out pin on graphInputs node
        # this should expose input pin on compound node
        outPin = inputs1.addOutPin()
        man.Tick(0.02)
        self.assertEqual(
            len(subgraphNodeInstance.namePinInputsMap), 1, "failed to expose input pin"
        )
        self.assertEqual(
            list(subgraphNodeInstance.inputs.values())[0].name, outPin.name
        )
        self.assertEqual(outPin.optionEnabled(PinOptions.Dynamic), True)

        # change inner pin name and check it is reflected outside
        outPin.setName("first")
        self.assertEqual(
            list(subgraphNodeInstance.inputs.values())[0].name,
            outPin.name,
            "name is not synchronized",
        )

        # create input pin on graphOutputs node
        # this should expose output pin on compound node
        inPin = outputs1.addInPin()
        man.Tick(0.02)
        self.assertEqual(
            len(subgraphNodeInstance.namePinOutputsMap), 1, "failed to expose input pin"
        )
        self.assertEqual(
            list(subgraphNodeInstance.outputs.values())[0].name, inPin.name
        )
        self.assertEqual(inPin.optionEnabled(PinOptions.RenamingEnabled), True)

        # change inner pin name and check it is reflected outside
        inPin.setName("second")
        self.assertEqual(
            list(subgraphNodeInstance.outputs.values())[0].name,
            inPin.name,
            "name is not synchronized",
        )

        depthsBefore = [g.depth() for g in man.getAllGraphs()]

        nameBefore = subgraphNodeInstance.name
        saved = man.serialize()
        man.clear(keepRoot=False)
        self.assertEqual(man.activeGraph(), None)
        man.deserialize(saved)
        self.assertIsNotNone(man.activeGraph())
        nameAfter = man.getAllNodes(classNameFilters="compound")[0].name
        self.assertEqual(
            nameBefore,
            nameAfter,
            "names are incorrect {0} - {1}".format(nameBefore, nameAfter),
        )
        depthsAfter = [g.depth() for g in man.getAllGraphs()]
        self.assertEqual(
            Counter(depthsBefore),
            Counter(depthsAfter),
            "failed to restore graphs depths",
        )

    def test_any_pin_speed(self):
        packages = GET_PACKAGES()
        man = GraphManager()

        classNodes = packages["PyFlowBase"].GetNodeClasses()
        defaultLib = (
            packages["PyFlowBase"].GetFunctionLibraries()["DefaultLib"].getFunctions()
        )
        arrayLib = (
            packages["PyFlowBase"].GetFunctionLibraries()["ArrayLib"].getFunctions()
        )

        makeArrayNode = classNodes["makeArray"]("makeArray")
        arraySlice = NodeBase.initializeFromFunction(arrayLib["arraySlice"])
        arrayLen = NodeBase.initializeFromFunction(arrayLib["arrayElementCount"])
        makeInt0 = NodeBase.initializeFromFunction(defaultLib["makeInt"])
        makeInt1 = NodeBase.initializeFromFunction(defaultLib["makeInt"])
        makeInt2 = NodeBase.initializeFromFunction(defaultLib["makeInt"])
        makeInt3 = NodeBase.initializeFromFunction(defaultLib["makeInt"])
        printNode = classNodes["consoleOutput"]("printer")
        printNode1 = classNodes["consoleOutput"]("printer")
        printNode2 = classNodes["consoleOutput"]("printer")

        man.activeGraph().addNode(makeArrayNode)
        man.activeGraph().addNode(arraySlice)
        man.activeGraph().addNode(arrayLen)
        man.activeGraph().addNode(makeInt0)
        man.activeGraph().addNode(makeInt1)
        man.activeGraph().addNode(makeInt2)
        man.activeGraph().addNode(makeInt3)
        man.activeGraph().addNode(printNode)
        man.activeGraph().addNode(printNode1)
        man.activeGraph().addNode(printNode2)

        makeInt0["i"].setData(0)
        makeInt1["i"].setData(1)
        makeInt2["i"].setData(2)
        makeInt3["i"].setData(3)

        arraySlice["start"].setData(1)
        arraySlice["end"].setData(3)

        connectPinsByIndexes(makeInt0, 0, makeArrayNode, 0)
        connectPinsByIndexes(makeInt1, 0, makeArrayNode, 0)
        connectPinsByIndexes(makeInt2, 0, makeArrayNode, 0)
        connectPinsByIndexes(makeInt3, 0, makeArrayNode, 0)
        connectPinsByIndexes(makeArrayNode, 0, arraySlice, 0)
        connectPinsByIndexes(arraySlice, 0, printNode, 1)
        connectPinsByIndexes(arraySlice, 0, arrayLen, 0)
        connectPinsByIndexes(arrayLen, 0, printNode1, 1)
        connectPinsByIndexes(printNode, 0, printNode1, 0)
        connectPinsByIndexes(printNode1, 0, printNode2, 0)

        start = time.process_time()
        printNode[DEFAULT_IN_EXEC_NAME].call()
        print("DELTA:", time.process_time() - start)


if __name__ == "__main__":
    unittest.main()
